﻿using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.Devices;
using HamcoWcs.Service.Common;
using HamcoWcs.Models.Events;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HamcoWcs.Entitys.Devices;
using Microsoft.EntityFrameworkCore.Diagnostics;
using HamcoWcs.DAL;
using AutoMapper;
using Microsoft.Extensions.DependencyInjection;
using System.Threading;
using HamcoWcs.Contract.MachineStatus;
using NPOI.SS.Formula.Functions;
using Microsoft.EntityFrameworkCore;

namespace HamcoWcs.Service.MachineStatus
{
    [AutoInject(typeof(IMachineStateService), InjectType.Single)]
    public class MachineStateService : IMachineStateService
    {
        private readonly IServiceScopeFactory _scopeFactory;
        private readonly IMapper _mapper;
        private ConcurrentDictionary<string, MachineStateMode> MachineStateDic = new ConcurrentDictionary<string, MachineStateMode>();
        private ConcurrentQueue<MachineState> MachineStateQueue = new ConcurrentQueue<MachineState>();
        private object _lock = new object();

        private readonly static int hour = 60 * 60;
        private readonly static int day = 24 * hour;
        private int month = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month) * day;
        private int year = DateTime.IsLeapYear(DateTime.Now.Year) ? 366 * day : 365 * day;
        public MachineStateService(IServiceScopeFactory scopeFactory, IMapper mapper)
        {
            _mapper = mapper;
            _scopeFactory = scopeFactory;
        }
        public void SaveMachineState(string machineName, EnumMachineState machineState)
        {
            if (MachineStateDic.ContainsKey(machineName))
            {
                MachineStateDic[machineName].DevicesStateSaveEvent += OnSaveMachineState;
                MachineStateDic[machineName].UpateData(machineState);
            }
            else
            {
                var machine = new MachineStateMode(machineName);
                machine.DevicesStateSaveEvent += OnSaveMachineState;
                machine.UpateData(machineState);
                MachineStateDic.TryAdd(machineName, machine);
            }
            MachineStateDic[machineName].DevicesStateSaveEvent -= OnSaveMachineState;

        }

        public List<MachineStateDto> SelectMachineState(MachineStateQueryModel model)
        {
            List<MachineStateDto> query = new List<MachineStateDto>();
            double totelTime = 0;
            DateTime startTime;
            DateTime endTime;
            decimal other = 0;
            if (model.Type.IsNullOrEmpty())
            {
                startTime = model.StartTime ?? DateTime.Now;
                endTime = model.EndTime ?? DateTime.Now;
            }
            else
            {
                startTime = model.Type switch
                {
                    "hour" => Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:00:00")),
                    "day" => Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd 00:00:00")),
                    "month" => Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-01 00:00:00")),
                    "year" => Convert.ToDateTime(DateTime.Now.ToString("yyyy-01-01 00:00:00")),
                    _ => Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                };
                endTime = model.Type switch
                {
                    "hour" => Convert.ToDateTime(DateTime.Now.AddHours(1).ToString("yyyy-MM-dd HH:00:00")),
                    "day" => Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd 00:00:00")),
                    "month" => Convert.ToDateTime(DateTime.Now.AddMonths(1).ToString("yyyy-MM-01 00:00:00")),
                    "year" => Convert.ToDateTime(DateTime.Now.AddYears(1).ToString("yyyy-01-01 00:00:00")),
                    _ => Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                };
            }
            using (var scope = _scopeFactory.CreateScope())
            {
                var _wcsDbContext = scope.ServiceProvider.GetRequiredService<WcsDbContext>();
                var itmes =  _wcsDbContext.MachineStates.
                                            Where(x =>
                                                x.MachineName.Contains(model.MachineName) &&
                                                x.StrartTime > startTime &&
                                                x.EndTime < endTime
                                                ).ToList();
                itmes.ForEach(x => totelTime += x.MachineDescription);
                query = itmes.AsQueryable()
                             .GroupBy(x => x.MachineStatus).AsQueryable()
                             .Select(x => new MachineStateDto()
                             {
                                 MachineName = x.Key,
                                 Proportion = Math.Floor(Math.Round(decimal.Parse(((x.ToList().Sum(c => c.MachineDescription)) / totelTime).ToString("0.000")), 2) * 100)
                             }).ToList();
                
            }
            if(query != null && query.Count > 0)
            {
                query.ForEach(x =>
                {
                    if (x.MachineName != "RUN")
                    {
                        other += x.Proportion;
                    }
                });
                query.Where(x => x.MachineName == "RUN").FirstOrDefault().Proportion = (100 - other);
            }
            
            return query;
        }
        private void OnSaveMachineState(object sender, DevicesStateSaveEvent e)
        {
            if (e.MachineState != null)
            {
                using (var scope = _scopeFactory.CreateScope())
                {
                    var _wcsDbContext = scope.ServiceProvider.GetRequiredService<WcsDbContext>();
                    _wcsDbContext.MachineStates.Add(e.MachineState);
                    _wcsDbContext.SaveChanges();
                }
            }
        }


    }
}
